#include <map>
#include <vector>
#include <string>
#include "smartpipe.h"

using namespace std;
using namespace sp;

void registe(){
    Image::Crop::cropWithInput::registe();
    Image::Crop::cropWithParas::registe();
    Image::Gen::genFromDisk::registe();
    Image::Gen::genFromMemory::registe();
    Image::Mark::landMark::registe();
    Image::Mark::markWithString::registe();
    Image::Pull::pullFromRtsp::registe();
    Image::Push::pushWithRtsp::registe();
    Image::Push::pushWithRtmp::registe();
    Image::Resize::letterBoxResize::registe();
    Image::Resize::resize::registe();
    Image::Save::markAndSave::registe();
    Image::Save::save::registe();
    Image::Trans::trans::registe();
    Model::BlazePose::blazepose_inference::registe();
    Model::BlazePose::blazepose_postprocess::registe();
    Model::BlazePose::blazepose_preprocess::registe();
    Model::Group::groupByBatch::registe();
    Model::Split::splitByShape::registe();
    Model::Trans::transferToDeviceMemory::registe();
    Model::Trans::transferToHostMemory::registe();
    Model::Yolo::yolo_complete::registe();
    Model::Yolo::yolo_preprocess::registe();
    Model::Yolo::yolo_inference::registe();
    Model::Yolo::yolo_postprocess::registe();
    Model::Retinanet::retinanet_preprocess::registe();
    Model::Retinanet::retinanet_inference::registe();
    Model::Retinanet::retinanet_postprocess::registe();
    Model::LPRnet::lprnet_preprocess::registe();
    Model::LPRnet::lprnet_inference::registe();
    Model::LPRnet::lprnet_postprocess::registe();
    Model::Openpose::openpose_preprocess::registe();
    Model::Openpose::openpose_inference::registe();
    Model::Openpose::openpose_postprocess::registe();
    Tool::Group::groupByRequestId::registe();
    Tool::Split::splitByFlowId::registe();
}

char* DATA_SOURCE;
char* DATA_TARGET;

char* input_video_data_ptr;
char* output_video_data_ptr;

// 共用参数
string video_path = "/data/lx/SmartPipe/data_source/videos/World_Of_Dance.mp4";      // 视频路径
string save_path = "/data/lx/SmartPipe/apps/people_pose_estimate/out.avi";  // 输出路径
int video_channels = 1;         // 视频路数
long cnt = 23*240;              // 单路视频帧数 257
int fps = 600;                  // 单路视频帧率
int w = 1280;                   // 视频宽度
int h = 720;                    // 视频高度

// 单路视频 离线运行 指定部署方式
void app_run_offline1(SharedMemoryManager& smm, Gpu_SharedMemoryManager& gpu_smm){
    // 将视频加载到内存中
    SharedMemoryPool input_video_pool = smm.createSharedMemoryPool("input_video", Cv_Mat_Data_1280_720_Memory, cnt);
    SharedMemoryPool output_video_pool = smm.createSharedMemoryPool("output_video", Cv_Mat_Data_1280_720_Memory, cnt);
    input_video_data_ptr = input_video_pool.getDataPtr();
    output_video_data_ptr = output_video_pool.getDataPtr();
    Image::Gen::genFromDisk f_start(video_path, input_video_data_ptr, cnt, fps, w, h);
    f_start.run();
    // 构造app
    Function* f0 = new Image::Gen::genFromMemory(input_video_data_ptr, cnt, fps, w, h);
    Function* f1 = new Image::Resize::resize(256, 256); // blazepose 的大小待定
    Function* f2 = new Model::BlazePose::blazepose_preprocess(256, 256);
    Function* f3 = new Model::Group::groupByBatch(16);
    Function* f4 = new Model::Trans::transferToDeviceMemory();
    Function* f5 = new Model::BlazePose::blazepose_inference(256, 256);
    Function* f6 = new Model::Trans::transferToHostMemory();
    Function* f7 = new Model::Split::splitByShape();
    Function* f8 = new Model::BlazePose::blazepose_postprocess(256, 256);
    Function* f9 = new Image::Mark::landMark();
    Function* f10 = new Image::Save::save(save_path, output_video_data_ptr, cnt, fps, w, h);
    // 连接逻辑关系
    connect(f0, f9);
    connectOneByOne(11, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10);
    // 部署表
    map<short, vector<Function*>> Fs_map; // Fs_map Function映射到CPU逻辑核（Excutor)
    map<short, vector<int>> Gpus_map;     // Gpus_map GPU映射到CPU逻辑核
    Fs_map[0] = {f0};
    Fs_map[1] = {f1};
    Fs_map[2] = {f2};
    Fs_map[3] = {f3};
    Fs_map[4] = {f4, f6};
    Fs_map[5] = {f5};
    Fs_map[6] = {f7};
    Fs_map[7] = {f8};
    Fs_map[8] = {f9};
    Fs_map[9] = {f10};
    Gpus_map[0] = {4, 5};
    // 构造app
    App app(0, Fs_map, Gpus_map, &smm, &gpu_smm); // 构造App, app_id, Fs_map, Gpus_map, smm, gpu_smm
    // 运行app
    app.check();
    app.printMsg();
    app.init();
    app.run();
    app.waitForComplete();
    // 检查是否存在内存泄露
    smm.check();
    // 将输出视频保存到磁盘
    Image::Save::save f_end(save_path, output_video_data_ptr, cnt, fps, w, h);
    f_end.run();
}

// 单路视频 离线运行 指定部署方式 指定检测框 更精准
void app_run_offline2(SharedMemoryManager& smm, Gpu_SharedMemoryManager& gpu_smm){
    // 将视频加载到内存中
    SharedMemoryPool input_video_pool = smm.createSharedMemoryPool("input_video", Cv_Mat_Data_1280_720_Memory, cnt);
    SharedMemoryPool output_video_pool = smm.createSharedMemoryPool("output_video", Cv_Mat_Data_1280_720_Memory, cnt);
    input_video_data_ptr = input_video_pool.getDataPtr();
    output_video_data_ptr = output_video_pool.getDataPtr();
    Image::Gen::genFromDisk f_start(video_path, input_video_data_ptr, cnt, fps, w, h);
    f_start.run();
    // 构造app
    Function* f0 = new Image::Gen::genFromMemory(input_video_data_ptr, cnt, fps, w, h);
    Function* f1 = new Image::Crop::cropWithParas(450, 830, 130, 680);    // 指定区域
    Function* f2 = new Image::Resize::letterBoxResize(256, 256);                  
    Function* f3 = new Model::BlazePose::blazepose_preprocess(256, 256);
    Function* f4 = new Model::Group::groupByBatch(16);
    Function* f5 = new Model::Trans::transferToDeviceMemory();
    Function* f6 = new Model::BlazePose::blazepose_inference(256, 256);
    Function* f7 = new Model::Trans::transferToHostMemory();
    Function* f8 = new Model::Split::splitByShape();
    Function* f9 = new Model::BlazePose::blazepose_postprocess(256, 256);
    Function* f10 = new Image::Mark::landMark(450, 830, 130, 680);        // MAT MESH RECT
    Function* f11 = new Image::Save::save(save_path, output_video_data_ptr, cnt, fps, w, h);
    // 连接逻辑关系
    connect(f0, f10);
    connectOneByOne(12, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11);
    // 扩展实例个数
    Function* f3_0, *f3_1, *f3_2;
    expand(f3, 3, &f3_0, &f3_1, &f3_2);
    Function* f4_0, *f4_1, *f4_2;
    expand(f4, 3, &f4_0, &f4_1, &f4_2);
    Function* f9_0, *f9_1, *f9_2, *f9_3;
    expand(f9, 4, &f9_0, &f9_1, &f9_2, &f9_3);
    // 部署表
    map<short, vector<Function*>> Fs_map; // Fs_map Function映射到CPU逻辑核（Excutor)
    map<short, vector<int>> Gpus_map;     // Gpus_map GPU映射到CPU逻辑核
    Fs_map[0] = {f0};
    Fs_map[1] = {f1};
    Fs_map[2] = {f2};
    Fs_map[3] = {f3};
    Fs_map[4] = {f3_0};
    Fs_map[5] = {f3_1};
    Fs_map[6] = {f3_2};
    Fs_map[7] = {f4};
    Fs_map[8] = {f4_0};
    Fs_map[9] = {f4_1};
    Fs_map[10] = {f4_2};
    Fs_map[11] = {f5, f7};
    Fs_map[12] = {f6};
    Fs_map[13] = {f8};
    Fs_map[14] = {f9};
    Fs_map[15] = {f9_0};
    Fs_map[16] = {f9_1};
    Fs_map[17] = {f9_2};
    Fs_map[18] = {f9_3};
    Fs_map[19] = {f10};
    Fs_map[20] = {f11};
    Gpus_map[0] = {11, 12};
    // 构造app
    App app(0, Fs_map, Gpus_map, &smm, &gpu_smm); // 构造App, app_id, Fs_map, Gpus_map, smm, gpu_smm
    // 运行app
    app.check();
    app.printMsg();
    app.init();
    app.run();
    app.waitForComplete();
    // 检查是否存在内存泄露
    smm.check();
    // 将输出视频保存到磁盘
    Image::Save::save f_end(save_path, output_video_data_ptr, cnt, fps, w, h);
    f_end.run();
}

int main(){
    // 注册
    registe();
    // 声明共享内存管理对象
    SharedMemoryManager smm;
    Gpu_SharedMemoryManager gpu_smm;
    // 单路视频离线测试
    app_run_offline2(smm, gpu_smm);
    // 单路视频在线测试
    // app_run_online(smm, gpu_smm);
    // 多路视频在线测试，评测部署的方式运行
    // app_run_multiFlow_online_PAD(smm, gpu_smm);
}